﻿// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using NuGet.Services.Entities;
using NuGet.Services.GitHub.Ingest;
using NuGetGallery;

namespace GitHubVulnerabilities2Db.Gallery
{
    public class GalleryDbVulnerabilityWriter : IVulnerabilityWriter
    {
        private readonly IPackageVulnerabilitiesManagementService _packageVulnerabilityService;
        private readonly ILogger<GalleryDbVulnerabilityWriter> _logger;

        public GalleryDbVulnerabilityWriter(
            IPackageVulnerabilitiesManagementService packageVulnerabilityService,
            ILogger<GalleryDbVulnerabilityWriter> logger)
        {
            _packageVulnerabilityService = packageVulnerabilityService ?? throw new ArgumentNullException(nameof(packageVulnerabilityService));
            _logger = logger ?? throw new ArgumentNullException(nameof(logger));
        }

        public Task FlushAsync(string outputFileName = null)
        {
            // This method is unused for this implementation.
            return Task.CompletedTask;
        }

        public async Task<int> WriteVulnerabilitiesAsync(IEnumerable<Tuple<PackageVulnerability,bool>> vulnerabilities)
        {
            var writtenVulerabilityCount = 0;
            _logger.LogDebug("Starting write of {VulnerabilityCount} vulnerabilities to Gallery DB", vulnerabilities.Count());

            foreach(var vulnerability in vulnerabilities)
            {
                var dbVulnerability = vulnerability.Item1;
                var wasWithdrawn = vulnerability.Item2;
                await WriteVulnerabilityAsync(dbVulnerability, wasWithdrawn);
                writtenVulerabilityCount++;
            }

            _logger.LogDebug("Wrote {WrittenVulnerabilityCount} vulnerabilities.", writtenVulerabilityCount);
            return writtenVulerabilityCount;
        }

        public async Task WriteVulnerabilityAsync(PackageVulnerability vulnerability, bool wasWithdrawn = false)
        {
            try
            {
                await _packageVulnerabilityService.UpdateVulnerabilityAsync(vulnerability, wasWithdrawn);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Failed to write vulnerability {GitHubAdvisoryUrl}", vulnerability.AdvisoryUrl);
                throw;
            }
        }
    }
}
